﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using Ast.Core.Forms;
using Ast.Core.Services;
using Ast.Framework.Forms;
using Castle.Core.Logging;

namespace Ast
{
    [FormMetadata(FormType.Module, IsTabForm = true)]
    public partial class ModuleForm : Form
    {
        private readonly IPsLoadedModuleListService _psLoadedModuleListService;

        public ModuleForm(IPsLoadedModuleListService psLoadedModuleListService)
        {
            _psLoadedModuleListService = psLoadedModuleListService;

            InitializeComponent();

            Logger = NullLogger.Instance;
        }

        public ILogger Logger { get; set; }

        private void ModuleForm_Load(object sender, EventArgs e)
        {
            lvModules.ApplyColumnSorter();
            btnReload.PerformClick();
        }

        private async void btnReload_Click(object sender, EventArgs e)
        {
            var items = new List<ListViewItem>();

            await Task.Run(() => _psLoadedModuleListService.ListModules((entry, path, name) =>
            {
                var moduleViewItem = new ModuleViewItem
                {
                    Name = name,
                    Address = entry.DllBase,
                    Size = entry.SizeOfImage,
                    Path = path
                };

                var listViewItem = new ListViewItem(new[]
                {
                    moduleViewItem.Name,
                    string.Format("0x{0:x}", moduleViewItem.Address.ToInt32()),
                    string.Format("0x{0:x8}", moduleViewItem.Size),
                    moduleViewItem.Path,
                })
                {
                    Tag = moduleViewItem
                };

                items.Add(listViewItem);

                return true;
            })).ConfigureAwait(false);

            Logger.InfoFormat("found {0} modules", items.Count);

            // update view
            Invoke(new Action(() =>
            {
                lvModules.BeginUpdate();
                lvModules.Items.Clear();
                lvModules.Items.AddRange(items.ToArray());
                lvModules.AutoResizeColumns();
                lvModules.EndUpdate();
            }));
        }
    }

    public class ModuleViewItem
    {
        public string Name { get; set; }
        public IntPtr Address { get; set; }
        public long Size { get; set; }
        public string Path { get; set; }
    }
}